package org.luckyjourney.limit;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.luckyjourney.constant.RedisConstant;
import org.luckyjourney.exception.LimiterException;
import org.luckyjourney.holder.UserHolder;
import org.luckyjourney.util.RedisCacheUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Collections;

@Aspect
@Component
public class LimiterAop {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String LIMIT_LUA_SCRIPT =
            "local key = KEYS[1]\n" +
                    "local limit = tonumber(ARGV[1])\n" +
                    "local expire = tonumber(ARGV[2])\n" +
                    "local current = redis.call('get', key)\n" +
                    "if current == false then\n" +
                    "    redis.call('setex', key, expire/1000, 1)\n" +
                    "    return 1\n" +
                    "else\n" +
                    "    if tonumber(current) >= limit then\n" +
                    "        return -1\n" +
                    "    end\n" +
                    "    return redis.call('incr', key)\n" +
                    "end";

    // 修正切点表达式
    @Around("@annotation(org.luckyjourney.limit.Limit)")  // 使用完整注解路径
    public Object limitRestriction(ProceedingJoinPoint joinPoint) throws Throwable {
        // 1. 获取注解实例
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Limit limiter = method.getAnnotation(Limit.class);

        // 2. 提取限流参数
        Long userId = UserHolder.get();
        int limitCount = limiter.limit();
        String msg = limiter.msg();
        long time = limiter.time();
        String key = RedisConstant.VIDEO_LIMIT + userId;

        // 3. 执行Lua限流判断
        Long result = (Long) redisTemplate.execute(
                new DefaultRedisScript<>(LIMIT_LUA_SCRIPT, Long.class),
                Collections.singletonList(key),
                limitCount, time
        );

        // 4. 处理限流结果
        if (result != null && result == -1L) {
            throw new LimiterException(msg);
        }

        // 5. 执行业务方法
        return joinPoint.proceed();
    }
}